#include <typeinfo>
#include <iostream>

#include <cubefs/core/types.hpp>
#include <cubefs/core/tools/bitmap.hpp>
#include <cubefs/core/tools/types/typehash.hpp>

using namespace std;
using cubefs::NullType;
using cubefs::Int;
using namespace cubefs::core::tools::bitmap;
using namespace cubefs::core::tools::types;



template <typename NameType, typename BaseType = NullType>
struct Profile: public BaseType {
    typedef NameType Name;
    typedef BaseType Base;
};

class RootProfileName               {};
class FirstDerivedProfileName       {};
class SecondDerivedProfileName      {};
class ThirdDerivedProfileName        {};

typedef Profile<RootProfileName>                                                RootProfile;
typedef Profile<FirstDerivedProfileName,  RootProfile>                          FirstDerivedProfile;
typedef Profile<SecondDerivedProfileName, RootProfile>                          SecondDerivedProfile;
typedef Profile<ThirdDerivedProfileName,  RootProfile>                          ThirdDerivedProfile;






template <typename TypeType>
struct LocatableBase {
    typedef TypeType Type;
};

class TypeNotFound;

template <typename TargetProfile, typename Profile, typename Default = TypeNotFound>
struct Locatable: public LocatableBase<
            typename Locatable <
                typename TargetProfile::Base,
                Profile,
                Default
            >::Type
> {};

template <typename Profile, typename Default>
struct Locatable<NullType, Profile, Default>: public LocatableBase<Default> {};


template <typename Profile, typename Default>
struct Locatable<RootProfile, Profile, Default>:
        public LocatableBase<Locatable<RootProfile, Profile, Default> > {

    static void dump() {
        cout<<"RootProfile"<<endl;
    }
};

template <typename Profile, typename Default>
struct Locatable<FirstDerivedProfile, Profile, Default>:
        public LocatableBase<Locatable<FirstDerivedProfile, Profile, Default> > {
    
    static void dump() {
        cout<<"FirstDerivedProfile"<<endl;
    }
};


template <typename Profile, typename Default>
struct Locatable<SecondDerivedProfile, Profile, Default>:
        public LocatableBase<Locatable<SecondDerivedProfile, Profile, Default> > {
    
    static void dump() {
        cout<<"SecondDerivedProfile"<<endl;
    }
};


#pragma pack(1)

struct A {
    int         a_;
    char        b_;
    long long   c_;

    Int GetHashCode() {
        Int values[] = {
            Hash(&a_),
            Hash(&b_),
            Hash(&c_),
        };
        return GetListHash(values, 3);
    }

    static Int hash() {
        A* a = NULL;
        return a->GetHashCode();
    }
};

#pragma pack()

int main() {

    Locatable<FirstDerivedProfile,  FirstDerivedProfile>::Type  ::dump();
    Locatable<SecondDerivedProfile, SecondDerivedProfile>::Type ::dump();
    Locatable<ThirdDerivedProfile,  ThirdDerivedProfile>::Type  ::dump();

    cout<<endl;

    cout<<"A: "<<A::hash()<<endl;

    return 0;
}
